package org.cuit.lmq.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.cuit.lmq.constants.enums.BodyStatusEnum;
import org.cuit.lmq.domain.common.BaseContextHolder;
import org.cuit.lmq.domain.po.BodyInfo;
import org.cuit.lmq.mapper.BodyInfoMapper;
import org.cuit.lmq.service.BodyInfoService;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author Seon
 * @since 2023-03-03
 */
@Service
public class BodyInfoServiceImpl extends ServiceImpl<BodyInfoMapper, BodyInfo> implements BodyInfoService {

    /**
     * 其实这里的实现有点复杂了，应该写成是七个身体数据直接放到一个vo里面返回比较好一些，这样子不太规范。
     *
     * @return
     */
    @Override
    public Map<String, List<List<String>>> statisticsBodyInfo() {

        long userId = BaseContextHolder.getCurrentUserId();
        SimpleDateFormat sdt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        Map<String, List<List<String>>> data = new HashMap<>();
        List<List<String>> container = new ArrayList<>();
        List<String> XDates, YNumbers;

        LambdaQueryWrapper<BodyInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BodyInfo::getUserId, userId);
        wrapper.orderByDesc(BodyInfo::getCreateTime).last("limit 0,7");
        List<BodyInfo> list = this.list(wrapper);

        XDates = list.parallelStream().map(item -> sdt.format(item.getCreateTime())).collect(Collectors.toList());
        YNumbers = list.parallelStream().map(item -> item.getWeight().toString()).collect(Collectors.toList());
        container.add(XDates);
        container.add(YNumbers);
        data.put("weight", container);

        // bmi信息封装
        container = new ArrayList<>();
        YNumbers = list.parallelStream().map(item -> String.format("%.2f", item.getBmi())).collect(Collectors.toList());
        container.add(XDates);
        container.add(YNumbers);
        data.put("bmi", container);

        // 体脂率信息封装
        container = new ArrayList<>();
        YNumbers = list.parallelStream().map(item -> item.getFatRate().toString()).collect(Collectors.toList());
        container.add(XDates);
        container.add(YNumbers);
        data.put("fat_rate", container);

        // 身体状态信息封装
        container = new ArrayList<>();
        YNumbers = list.parallelStream().map(item -> item.getBodyStatus().toString()).collect(Collectors.toList());
        container.add(XDates);
        container.add(YNumbers);
        data.put("body_status", container);

        return data;
    }

    @Override
    public Map<String, String> peakBodyInfo() {
        Map<String, String> data = new HashMap<>();
        long userId = BaseContextHolder.getCurrentUserId();
        double weightMax, weightMin;
        double bmiMax, bmiMin;
        double fatRateMax, fatRateMin;
        BodyStatusEnum statusBest, statusWorst;

        LambdaQueryWrapper<BodyInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BodyInfo::getUserId, userId);
        List<BodyInfo> list = this.list(wrapper);
        /**
         * 比较大小的精髓，流编程！优雅，太优雅了！
         */
        weightMax = list.parallelStream().mapToDouble(BodyInfo::getWeight).max().orElse(-1D);
        weightMin = list.parallelStream().mapToDouble(BodyInfo::getWeight).min().orElse(-1D);

        bmiMax = list.parallelStream().mapToDouble(BodyInfo::getBmi).max().orElse(-1D);
        bmiMin = list.parallelStream().mapToDouble(BodyInfo::getBmi).min().orElse(-1D);

        fatRateMax = list.parallelStream().mapToDouble(BodyInfo::getFatRate).max().orElse(-1D);
        fatRateMin = list.parallelStream().mapToDouble(BodyInfo::getFatRate).min().orElse(-1D);

        statusWorst = list.parallelStream().map(BodyInfo::getBodyStatus).
                min(Comparator.comparingInt(Enum::ordinal)).orElse(BodyStatusEnum.BEAUTIFUL_HANDSOME);

        statusBest = list.parallelStream().map(BodyInfo::getBodyStatus).
                max(Comparator.comparingInt(Enum::ordinal)).orElse(BodyStatusEnum.BEAUTIFUL_HANDSOME);


        String weightData = String.format("%.2f", weightMax) + "-" + String.format("%.2f", weightMin);
        String bmiData = String.format("%.2f", bmiMax) + "-" + String.format("%.2f", bmiMin);
        String fatRateData = String.format("%.2f", fatRateMax) + "-" + String.format("%.2f", fatRateMin);
        String statusData = statusBest.getName() + "-" + statusWorst.getName();

        data.put("weightData", weightData);
        data.put("bmiData", bmiData);
        data.put("fatRateData", fatRateData);
        data.put("statusData", statusData);
        return data;
    }

    @Override
    public BodyStatusEnum judgeBodyStatus(BodyInfo bodyInfo) {
        double bmi = bodyInfo.getWeight() / Math.pow(bodyInfo.getHeight() / 100, 2);
        if (bmi < 17) {
            return BodyStatusEnum.SO_WEAK;
        } else if (bmi >= 17 && bmi < 18.5) {
            return BodyStatusEnum.EAT_MORE;
        } else if (bmi >= 18.5 && bmi < 23) {
            return BodyStatusEnum.BEAUTIFUL_HANDSOME;
        } else if (bmi >= 23 && bmi < 28) {
            return BodyStatusEnum.FAT;
        } else {
            return BodyStatusEnum.NEED_LOSE_WEIGHT;
        }
    }
}
